package edu.neusoft.lyc.topic_one;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * User：lyc
 * Date：2017-11-25
 * Time：11:50
 * Description：NIO示例代码
 */
public class NewIO {
    private Selector selector;

    public static void main(String[] args) {
        NewIO nio = new NewIO();
        nio.initServer(8000);
        nio.listen();
    }

    /**
     * 初始化服务端
     *
     * @param port 端口号
     */
    public void initServer(int port) {
        try {
            //获取服务端通道
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            //设置通道为非阻塞
            serverChannel.configureBlocking(false);
            //绑定服务端端口
            serverChannel.socket().bind(new InetSocketAddress(port));
            //获取通道管理器
            this.selector = Selector.open();
            //将通道管理器与服务端通道绑定并注册接收客户端连接事件驱动
            //当相关事件到达时，selector.select()会返回，否则会一直阻塞
            serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 采用轮询方式监听selector上是否有需要处理的事件
     */
    public void listen() {
        try {
            //轮询访问selector
            while (true) {
                //当注册时间到达时，方法返回 1 ，否则会一直阻塞
                this.selector.select();
                //获得selector到达的事件的迭代器
                Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    //删除到达的事件，防止重复
                    iterator.remove();
                    handle(key);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据到达的事件类型调用不同的方法来处理
     *
     * @param key 到达的事件
     */
    private void handle(SelectionKey key) {
        if (key.isAcceptable()) {
            handleAcceptEvent(key);
        } else if (key.isReadable()) {
            handleReadEvent(key);
        }
    }

    private void handleReadEvent(SelectionKey key) {
        try {
            //获取1024大小的缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //获取客户端连接通道
            SocketChannel socketChannel = (SocketChannel) key.channel();
            //读取通道传输的数据
            int len = socketChannel.read(buffer);
            if (len > 0) {
                System.out.println("客户端发来消息>>>>" + new String(buffer.array(), 0, len));
                //向客户端回复
                socketChannel.write(ByteBuffer.wrap(new String("success<<<<").getBytes()));
            }else {
                System.out.println("客户端关闭");
                key.cancel();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void handleAcceptEvent(SelectionKey key) {
        try {
            //通过到达的事件获取与其绑定的服务端通道
            ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
            //获取服务端接收客户端的连接通道
            SocketChannel socketChannel = serverChannel.accept();
            System.out.println("检测到新的客户端连接");
            //设置为非阻塞
            socketChannel.configureBlocking(false);
            //为客户端连接通道注册读事件驱动
            socketChannel.register(this.selector, SelectionKey.OP_READ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
